有些門禁系統除了讀取卡號之外,還會讀取卡片內的資料,這時候如果想要開啟這類的門禁,就需要完整的模擬或拷貝卡片的資料。
如果我們已經有 M1 卡片的完整資料,就可以使用變色龍裝置完整模擬 M1 卡片,以下是一個完整模擬 M1 卡片的範例程式碼:
// 在測試網頁的開發者工具中執行 https://taichunmin.idv.tw/chameleon-ultra.js/test.html
await (async ultra => {
// 載入需要的常數
const { Buffer, DeviceMode, FreqType, Mf1EmuWriteMode, Slot, TagType } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
const slot = Slot.SLOT_1 // 使用卡槽 1
await ultra.cmdSlotChangeTagType(slot, TagType.MIFARE_1024) // 設定卡槽為 M1 卡片類型
await ultra.cmdSlotResetTagType(slot, TagType.MIFARE_1024) // 重設卡槽資料
await ultra.cmdSlotSetEnable(slot, FreqType.HF, true) // 啟用卡槽的高頻模擬
await ultra.cmdSlotSetActive(slot) // 切換到指定的卡槽
await ultra.cmdMf1SetAntiCollMode(false) // 設定卡槽使用額外設定的防碰撞資料
await ultra.cmdMf1SetDetectionEnable(false) // 關閉卡槽的偵測功能
await ultra.cmdMf1SetWriteMode(Mf1EmuWriteMode.NORMAL) // 設定卡槽的寫入模式
// 關閉 Gen1A 和 Gen2 魔術卡模擬
await ultra.cmdMf1SetGen1aMode(false)
await ultra.cmdMf1SetGen2Mode(false)
// 設定防碰撞資料
await ultra.cmdHf14aSetAntiCollData({
atqa: Buffer.from('0400', 'hex'),
sak: Buffer.from('08', 'hex'),
uid: Buffer.from('136d4a3d', 'hex'),
ats: Buffer.from('', 'hex'),
})
// 產生一個空白 M1 卡的資料並寫入變色龍
const dump = Buffer.alloc(1024)
dump.set(Buffer.from('136d4a3d090804000000000000000000', 'hex'), 0) // block 0
const blkAcl = Buffer.from('FFFFFFFFFFFFFF078069FFFFFFFFFFFF', 'hex')
for (let i = 0; i < 16; i++) dump.set(blkAcl, i * 64 + 48) // block 4n+3
for (const chunk of dump.chunk(256)) await ultra.cmdMf1EmuWriteBlock(chunk.byteOffset / 16, chunk)
// 儲存設定並切換裝置模式
await ultra.cmdSlotSaveSettings()
await ultra.cmdChangeDeviceMode(DeviceMode.TAG)
})(vm.ultra)
如果想要成本更低的選擇,也可以使用變色龍把 M1 卡片的資料拷貝到 UID 魔術卡內,但因為 UID 魔術卡問世的時間較早,所以如果遇到會挑卡的讀卡機,可能需要多試試其他的魔術卡。請把一個 UID 魔術卡放在變色龍裝置的正面,然後執行以下的程式碼:
// 在測試網頁的開發者工具中執行 https://taichunmin.idv.tw/chameleon-ultra.js/test.html
await (async ultra => {
const { Buffer } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
// 產生一個空白 M1 卡的資料並寫入 UID 魔術卡
const dump = Buffer.alloc(1024)
dump.set(Buffer.from('136d4a3d090804000000000000000000', 'hex'), 0) // block 0
const blkAcl = Buffer.from('FFFFFFFFFFFFFF078069FFFFFFFFFFFF', 'hex')
for (let i = 0; i < 16; i++) dump.set(blkAcl, i * 64 + 48) // block 4n+3
// 使用 UID 魔術卡的後門指令寫入所有區塊
await ultra.mf1Gen1aWriteBlocks(0, dump)
})(vm.ultra)
CUID 魔術卡需要有正確的金鑰及存取權限才能寫入,一個非加密的 CUID 卡金鑰通常是 FFFFFFFFFFFF
,在寫入資料到 CUID 魔術卡時,請務必再三確認即將寫入的資料,因為寫錯資料可能會導致魔術卡鎖死 (俗稱變磚)。請把一個非加密的 CUID 魔術卡放在變色龍裝置的正面,然後執行以下的程式碼:
// 在測試網頁的開發者工具中執行 https://taichunmin.idv.tw/chameleon-ultra.js/test.html
await (async ultra => {
const { Buffer, Mf1KeyType } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
// 產生一個空白 M1 卡的資料並寫入 CUID 魔術卡
const dump = Buffer.alloc(1024)
dump.set(Buffer.from('136d4a3d090804000000000000000000', 'hex'), 0) // block 0
const blkAcl = Buffer.from('FFFFFFFFFFFFFF078069FFFFFFFFFFFF', 'hex')
for (let i = 0; i < 16; i++) dump.set(blkAcl, i * 64 + 48) // block 4n+3
const keys = [Buffer.from('FFFFFFFFFFFF', 'hex')]
const sectors = dump.chunk(64)
let successCnt = 0
for (let i = 0; i < 16; i++) {
const { success } = await ultra.mf1WriteSectorByKeys(i, keys, sectors[i])
successCnt += _.sumBy(success, isBlockSuccess => isBlockSuccess ? 1 : 0)
}
console.log(`成功寫入 ${successCnt} 個區塊`)
})(vm.ultra)
如果寫入完成後,要特別確認成功的數量是不是 64 個區塊,如果不是就代表有部分區塊寫入失敗,下圖是均民故意放了一張 UID 魔術卡在變色龍裝置的正面,因為區塊 0 無法使用普通的寫入指令,所以只成功寫入了 63 個區塊: